<template>
  <van-field
    v-model="fieldLabel"
    :is-link="!readonly"
    :label="label"
    :placeholder="readonly ? '' : `请选择${label}`"
    :required="required"
    :rules="rules"
    clear-trigger="always"
    clearable
    readonly
    @cancel="emit('update:modelValue', null)"
    @click="!readonly && (showPicker = true)"
  />
  <van-calendar
    v-if="calendar"
    v-model:show="showPicker"
    :default-date="modelValue ? dayjs(modelValue).toDate() : new Date()"
    :max-date="maxDate"
    :min-date="minDate"
    first-day-of-week="1"
    switch-mode="year-month"
    @confirm="onCalendarConfirm"
    @select="onCalendarSelect"
  />
  <van-popup v-else v-model:show="showPicker" position="bottom" round>
    <template v-if="category === 'date'">
      <van-date-picker
        v-model="datePicker"
        :max-date="maxDate"
        :min-date="minDate"
        title="选择日期"
        @cancel="showPicker = false"
        @confirm="onDatePickerConfirm"
      />
    </template>
    <template v-else-if="category === 'time'">
      <van-time-picker
        v-model="datePicker"
        :columns-type="['hour', 'minute', 'second']"
        :max-time="formatTime(maxDate, '23:59:59')"
        :min-time="formatTime(minDate, '00:00:00')"
        title="选择时间"
        @cancel="showPicker = false"
        @confirm="onTimePickerConfirm"
      />
    </template>
  </van-popup>
  <van-popup v-if="category === 'date-time'" v-model:show="showTimePicker" position="bottom" round>
    <van-time-picker
      v-model="datePicker"
      :columns-type="['hour', 'minute', 'second']"
      :max-time="formatTime(maxDate, '23:59:59')"
      :min-time="formatTime(minDate, '00:00:00')"
      title="选择时间"
      @cancel="showTimePicker = false"
      @confirm="onDateTimeConfirm"
    />
  </van-popup>
</template>

<script lang="ts" setup>
import { Ref } from 'vue'
import dayjs from 'dayjs'

const props = withDefaults(
  defineProps<{
    modelValue: string | null
    label: string
    rules?: Array<any>
    required?: boolean
    readonly?: boolean
    calendar?: boolean
    category?: 'date' | 'date-time' | 'time'
    format?: string
    minDate?: Date
    maxDate?: Date
  }>(),
  {
    rules: undefined,
    required: false,
    readonly: false,
    calendar: false,
    category: 'date',
    format: 'YYYY-MM-DD',
    minDate: undefined,
    maxDate: undefined
  }
)
const { modelValue, label, rules, required, readonly, category, calendar, minDate, maxDate, format } =
  toRefs(props)

const emit = defineEmits<{
  (e: 'update:modelValue', value: any): void
}>()

const showPicker: Ref<boolean> = ref(false)
const showTimePicker: Ref<boolean> = ref(false)
const fieldLabel: Ref<string> = ref(modelValue.value || '')
const datePicker: Ref<Array<string>> = ref([])
const date = new Date()

watch(
  () => fieldLabel.value,
  () => emit('update:modelValue', fieldLabel.value)
)

watch(
  () => modelValue.value,
  () => (fieldLabel.value = modelValue.value || '')
)

const onCalendarConfirm = (calendar: any) => {
  date.setFullYear(1900 + calendar.getYear(), calendar.getMonth(), calendar.getDate())
  fieldLabel.value = formatDate(date)
  showPicker.value = false
}
const onCalendarSelect = () => {
  if (category.value === 'date-time') {
    showTimePicker.value = true
  }
}
const onDatePickerConfirm = ({ selectedValues }: any) => {
  date.setFullYear(selectedValues[0], selectedValues[1] - 1, selectedValues[2])
  fieldLabel.value = formatDate(date)
  showPicker.value = false
}
const onTimePickerConfirm = ({ selectedValues }: any) => {
  date.setHours(selectedValues[0], selectedValues[1], selectedValues[2])
  fieldLabel.value = formatDate(date)
  showPicker.value = false
}
const onDateTimeConfirm = ({ selectedValues }: any) => {
  date.setHours(selectedValues[0], selectedValues[1], selectedValues[2])
  fieldLabel.value = formatDate(date)
  showTimePicker.value = false
}
const formatDate = (date: Date) => {
  return dayjs(date).format(format.value)
}
const formatTime = (date: Date | undefined, defaultDate: string) => {
  if (date) {
    return dayjs(date).format('HH:mm:ss')
  } else {
    return defaultDate
  }
}
</script>

<style lang="less" scoped></style>
